﻿#include "ComposedTable.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

using namespace std;

ToolTreeNode::ToolTreeNode(const string& name, const Children& children)
	: m_name(name), m_children(children)
{

}

void ToolTreeNode::addChildren(const Child& child)
{
	m_children.push_back(child);
}

std::string ToolTreeNode::getName() const
{
	return m_name;
}

ToolTreeNode::Children ToolTreeNode::getChildren() const
{
	return m_children;
}

//ComposedTable::ComposedTable(const char* filename)
//{
//	ifstream fin(filename);
//	string line;
//	
//	while (getline(fin, line))
//	{
//		istringstream ss(line);
//		ToolName toolName;
//		MaterialList materialList;
//		MaterialName materialName;
//		int num;
//		ss >> toolName;
//		while (ss >> materialName && ss >> num)
//			materialList.push_back(make_pair(materialName, num));
//		m_mapComposeTable[toolName] = materialList;
//	}
//}

ComposedTable::ComposedTable(const char* filename)
{
	ifstream fin(filename);
	string line;
	int i = 0;
	while (getline(fin, line))
	{
		istringstream ss(line);
		ToolName toolName;
		ss >> toolName;
		m_mapToolID[toolName] = i++;
		auto toolTreeNode = make_shared<ToolTreeNode>(toolName, ToolTreeNode::Children());
		MaterialName materialName;
		int num;
		while (ss >> materialName && ss >> num)
		{
			auto materialTreeNode = make_shared<ToolTreeNode>(materialName, ToolTreeNode::Children());
			ToolTreeNode::Child child = make_pair(materialTreeNode, num);
			toolTreeNode->addChildren(child);
		}
		m_mapToolTreeNode[toolName] = toolTreeNode;
	}
	fin.close();
}

void ComposedTable::printResult() const
{
	cout << "您的合成道具有：";
	for (const auto& e : m_mapTarget)
	{
		if (e.second > 1)
			cout << e.second << "*";
		cout << e.first << " ";
	}
	cout << endl;

	cout << "您需要的原材料有：" << endl;
	vector<string> sv;
	for (const auto& e : m_mapResult)
	{
		sv.push_back(e.first + ": " + to_string(e.second));
	}
	sort(sv.begin(), sv.end(), [&](const string& s1, const string& s2)
		{
			auto pos1 = m_mapToolID.find(s1.substr(0, s1.find(':')));
			auto pos2 = m_mapToolID.find(s2.substr(0, s2.find(':')));
			return pos1->second < pos2->second;
		});
	for (const auto& s : sv)
	{
		if (!s.empty())
			cout << s << endl;
	}
}

void ComposedTable::addProp(const ToolName& toolName, int num)
{
	m_mapTarget[toolName] += num;
	for (int i = 0; i < num; ++i)
	{
		auto originStr = calcCompositeBaseMaterial(toolName);
		//cout << toolName << " = " << originStr << endl;
		convertResult(originStr);
	}
}

vector<string> ComposedTable::splitString(const string& inputStr, const char split)
{
	std::istringstream iss(inputStr);
	vector<string> ret;
	string tmp;
	while (getline(iss, tmp, split))
	{
		if (!tmp.empty())
			ret.push_back(tmp);
	}
	return ret;
}

string ComposedTable::calcCompositeBaseMaterial(const ToolName& toolName)
{
	string ret;
	const auto& tool = m_mapToolTreeNode[toolName];
	const auto& children = tool->getChildren();
	if (children.size() == 0)
	{
		return toolName;	//toolName is a basic tool
	}

	for (const auto& child : children)
	{
		//ret += (to_string(child.second) + "*" + calcCompositeBaseMaterial(child.first->getName())) + ' ';
		if (child.second != 1)
			ret += (to_string(child.second) + "*");
		ret += (calcCompositeBaseMaterial(child.first->getName()) + ' ');
	}
	return ret;
}

void ComposedTable::convertResult(const string& input)
{
	vector<string> sv = splitString(input);
	for (const auto& s : sv)
	{
		extractResultFromStr(s);
	}
}

void ComposedTable::extractResultFromStr(const std::string& inputStr)
{
	std::istringstream input(inputStr);
	string buf;
	int multiple = 1;
	while (getline(input, buf, '*'))
	{
		try {
			int num = stoi(buf);
			multiple *= num;
		}
		catch (...) {
			//cout << "error occur" << endl;
		}
	}
	m_mapResult[buf] += multiple;
}
